using System;
using System.Collections.Generic;
using System.Threading;

using TeleTwitter.Lib;

namespace WpfTeleTwitter
{
	internal static class StatusManager
	{
		private static TimeSpan _interval = TimeSpan.FromMinutes(5);
		private static readonly Dictionary<Timeline, StatusList> _statusLists = new Dictionary<Timeline, StatusList>();

		private static Thread _updateThread;
		private static readonly AutoResetEvent _stopEvent = new AutoResetEvent(false);
		private static readonly ManualResetEvent _statusChanged = new ManualResetEvent(false);

		private static readonly object _statiToSendLock = new object();
		private static readonly Queue<string> _statiToSend = new Queue<string>();
		
		static StatusManager()
		{
			TwitterManager.Instance().TwitterApi = ApiType.XML;
		}

		#region Properties

		public static string UserName
		{
			get { return TwitterManager.Instance().Username; }
			set
			{
				if (_updateThread != null)
					throw new InvalidOperationException("Updater is running");
				TwitterManager.Instance().Username = value;
			}
		}

		public static string Password
		{
			get { return TwitterManager.Instance().Password; }
			set
			{
				if (_updateThread != null)
					throw new InvalidOperationException("Updater is running");
				TwitterManager.Instance().Password = value;
			}
		}
		
		public static TimeSpan Interval
		{
			get { return _interval; }
			set
			{
				if (_updateThread != null)
					throw new InvalidOperationException("Updater is running");
				_interval = value;
			}
		}

		#endregion

		public static bool Login()
		{
			try
			{
				return TwitterManager.Instance().CurrentUser != null;
			}
			catch
			{
				return false;
			}
		}
		
		public static StatusList Add(Timeline timeline)
		{
			if (_updateThread != null)
				throw new InvalidOperationException("Updater is running");

			StatusList statusList = new StatusList();
			_statusLists.Add(timeline, statusList);
			return statusList;
		}

		public static void Start()
		{
			if (_updateThread != null)
				throw new InvalidOperationException("Updater is running");

			_updateThread = new Thread(UpdateThread);
			_updateThread.Name = "UpdateThread";
			_updateThread.IsBackground = true;
			_updateThread.Start();
		}

		public static void Stop()
		{
			if (_updateThread == null)
				throw new InvalidOperationException("Updater is not running");

			_stopEvent.Set();
			_updateThread.Join();
			_updateThread = null;
		}

		public static void UpdateStatus(string status)
		{
			lock (_statiToSendLock)
			{
				_statiToSend.Enqueue(status);
				_statusChanged.Set();
			}
		}

		private static void UpdateThread(object o)
		{
			WaitHandle[] handles = new WaitHandle[] { _stopEvent, _statusChanged };
			int raisedEventIndex = -1;
			do
			{
				TimeSpan interval = _interval;

				if (raisedEventIndex == 1)
				{
					lock (_statiToSendLock)
					{
						if (_statiToSend.Count > 0)
						{
							foreach (string status in _statiToSend)
								TwitterManager.Instance().UpdateStatus(status);
							interval = TimeSpan.FromSeconds(2);
						}
						_statusChanged.Reset();
					}
				}

				foreach (KeyValuePair<Timeline, StatusList> pair2 in _statusLists)
				{
					UpdateTimeline(pair2.Key, pair2.Value);
				}

				raisedEventIndex = WaitHandle.WaitAny(handles, interval, false);
			} while (raisedEventIndex != 0);
		}

		private static void UpdateTimeline(Timeline timeline, StatusList statusList)
		{
			try
			{
				if (statusList.ListStatus == ListStatus.Uninitialized)
					statusList.OnListStatusChanged(ListStatus.Initializing);
				else
					statusList.OnListStatusChanged(ListStatus.Updating);

				List<Status> stati;
				if (statusList.MostRecentStatus == null)
					stati = TwitterManager.Instance().GetTimeline(timeline);
				else
					stati = TwitterManager.Instance().GetTimeline(timeline, statusList.MostRecentStatus.CreatedAt);

				foreach (Status status in stati)
				{
					statusList.Add(status);
				}

				statusList.OnListStatusChanged(ListStatus.Idle);
			}
			catch
			{
				statusList.OnListStatusChanged(ListStatus.Error);
			}
		}
	}
}
